<?php
/**
 *------------------------------------------------
 * Author: YYT[QQ:375776626]
 *------------------------------------------------
 */

class DbMysqli extends Db
{
    private static $_instance = null;

    public static function getInstance()
    {
        if (is_null(self::$_instance)) self::$_instance = new self();
        return self::$_instance;
    }

    private static $_connect = array();

    private function _connect()
    {
        $connectId = md5(serialize($this->config));

        if (isset(self::$_connect[$connectId])) return self::$_connect[$connectId];

        if ($this->config['db_long_connect'] == true) {
            if (substr(PHP_VERSION, 0, 3) < 5.3) throw new Exception(__METHOD__.' [PHP5.3以上才支持Mysqli长连接, 需将db_long_connect配置为false]');
        }

        $host = $this->config['db_long_connect'] == true ? 'p:'.$this->config['db_host'] : $this->config['db_host'];
        self::$_connect[$connectId] = new Mysqli($host,
            $this->config['db_user'],
            $this->config['db_password'],
            $this->config['db_name'],
            $this->config['db_port']);
        if (self::$_connect[$connectId]->connect_errno) {
            throw new Exception(__METHOD__.' [数据库连接失败: '.iconv('GBK', 'UTF-8', self::$_connect[$connectId]->connect_error).']');
        }
        self::$_connect[$connectId]->set_charset($this->config['db_charset']);
        return self::$_connect[$connectId];
    }

    public function escapeString($string)
    {
        $Mysqli = $this->_connect();
        return $Mysqli->real_escape_string($string);
    }

    public function query($sql, $method = '')
    {
        $startTime = microtime(true);
        $method = strtolower($method);
        $sql = $this->parse('prefix', $sql);

        $Mysqli = $this->_connect();
        if ($method == 'fetch' || $method == 'fetchall' || $method == 'query' || $method == 'count')
            $isSelect = true;

        if (isset($isSelect)) {
            $result = $stmt = $Mysqli->query($sql);
        } else {
            $stmt = $Mysqli->prepare($sql);
            if (!empty($stmt)) $result = $stmt->execute();
        }
        if (!$method) return $result;

        if (!$stmt) throw new Exception('SQL错误: '.$sql.'<br />错误提示: '.$Mysqli->error);

        $result = array();
        switch ($method) {
            case 'fetch':
                $result = $stmt->fetch_assoc();
                break;
            case 'fetchall':
                if (method_exists('mysqli_result', 'fetch_all')) { //Compatibility layer with PHP < 5.3
                    $result = $stmt->fetch_all(1);
                } else {
                    for ($result = array(); $tmp = $stmt->fetch_array(1);) $result[] = $tmp;
                }
                break;
            case 'count':
                $row = $stmt->fetch_assoc();
                $result = !empty($row) ? reset($row) : 0;
                break;
            case 'insert':
                $result = $Mysqli->insert_id;
                break;
            case 'update':
            case 'delete':
                $result = $stmt->affected_rows;
                break;
        }
        self::$countQuery++;
        $stopTime = microtime(true);
        Web::debug('[用时<font color="red">'.round(($stopTime - $startTime), 4).'</font>秒]: '.$sql);
        return $result === null ? array() : $result;
    }

    public function getFields()
    {
        if (!$this->table) return;
        $dbname = '';
        if (!empty($this->config['db_name']) && !stristr($this->table, $this->config['db_name'])) {
            $dbname = $this->config['db_name'].'.';
        }
        $cacheFile = Web::config('cache_path').'/db/'.$dbname.$this->table.'.php';
        if (is_file($cacheFile)) {
            return unserialize(str_replace('<?php exit();//', '', file_get_contents($cacheFile)));
        }
        $startTime = microtime(true);
        $Mysqli = $this->_connect();
        $sql = 'DESC '.$this->table;
        $query = $Mysqli->query($sql);
        if (!$query) {
            throw new Exception(__METHOD__.' [获取表'.$this->table.'字段失败: '.$Mysqli->error.']');
        }
        $fields = array();
        while ($row = $query->fetch_assoc()) {
            if ($row['Key'] == 'PRI') {
                $fields['pk'] = strtolower($row['Field']);
            } else {
                $fields[] = strtolower($row['Field']);
            }
        }
        //如果不存在主键，则提取第一个字段为主键
        if (!array_key_exists('pk', $fields)) $fields['pk'] = array_shift($fields);
        self::$countQuery++;
        if (!empty($fields['pk'])) {
            $stopTime = microtime(true);
            Web::debug('[用时<font color="red">'.round(($stopTime - $startTime), 4).'</font>秒]: '.$sql, 2);
            Web::makeDir(dirname($cacheFile));
            file_put_contents($cacheFile, '<?php exit();//'.serialize($fields));
            return $fields;
        }
    }

    public function beginTransaction()
    {
        $Mysqli = $this->_connect();
        $Mysqli->autocommit(false);
    }

    public function commit()
    {
        $Mysqli = $this->_connect();
        $Mysqli->commit();
        $Mysqli->autocommit(true);
    }

    public function rollBack()
    {
        $Mysqli = $this->_connect();
        $Mysqli->rollback();
        $Mysqli->autocommit(true);
    }

    public function lastInsertId()
    {
        $Mysqli = $this->_connect();
        return $Mysqli->insert_id;
    }

    public function getVersion()
    {
        $Mysqli = $this->_connect();
        return $Mysqli->server_info;
    }
}